package com.bjbn.service.impl;

import com.bjbn.entity.EqptMapping;
import com.bjbn.mapper.EqptMappingMapper;
import com.bjbn.service.EqptMappingCacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 资产映射缓存服务实现类
 */
@Slf4j
@Service
public class EqptMappingCacheServiceImpl implements EqptMappingCacheService {
    
    @Autowired
    private EqptMappingMapper eqptMappingMapper;
    
    // 内存缓存Map，使用ConcurrentHashMap保证线程安全
    private final Map<String, EqptMapping> eqptCodeCache = new ConcurrentHashMap<>();
    private final Map<String, EqptMapping> bmsCodeCache = new ConcurrentHashMap<>();
    private final Map<String, EqptMapping> assetCodeCache = new ConcurrentHashMap<>();
    private final Map<String, EqptMapping> baCodeCache = new ConcurrentHashMap<>();
    private final Map<String, List<EqptMapping>> assetTypeCache = new ConcurrentHashMap<>();
    
    // 缓存统计信息
    private final AtomicLong cacheHitCount = new AtomicLong(0);
    private final AtomicLong cacheMissCount = new AtomicLong(0);
    private final AtomicLong lastRefreshTime = new AtomicLong(0);
    private final AtomicLong refreshCount = new AtomicLong(0);
    
    /**
     * 项目启动后自动初始化缓存
     * 注意：这个方法会被 @PostConstruct 和 CommandLineRunner 调用
     * 但 refreshCache() 方法内部有重复调用保护
     */
    @PostConstruct
    public void initCache() {
        log.info("开始初始化资产映射缓存...");
        try {
            refreshCache();
            log.info("资产映射缓存初始化完成，共加载 {} 条记录", eqptCodeCache.size());
        } catch (Exception e) {
            log.error("资产映射缓存初始化失败", e);
        }
    }
    
    @Override
    public void refreshCache() {
        log.info("开始刷新资产映射缓存...");
        long startTime = System.currentTimeMillis();
        
        try {
            // 从数据库查询所有资产映射数据
            List<EqptMapping> allMappings = eqptMappingMapper.selectList(null);
            
            // 清空现有缓存
            clearCache();
            
            // 重新构建缓存
            for (EqptMapping mapping : allMappings) {
                if (mapping.getEqptCode() != null && !mapping.getEqptCode().trim().isEmpty()) {
                    eqptCodeCache.put(mapping.getEqptCode(), mapping);
                }
                if (mapping.getBmsCode() != null && !mapping.getBmsCode().trim().isEmpty()) {
                    bmsCodeCache.put(mapping.getBmsCode(), mapping);
                }
                if (mapping.getAssetCode() != null && !mapping.getAssetCode().trim().isEmpty()) {
                    assetCodeCache.put(mapping.getAssetCode(), mapping);
                }
                if (mapping.getBaCode() != null && !mapping.getBaCode().trim().isEmpty()) {
                    baCodeCache.put(mapping.getBaCode(), mapping);
                }
                if (mapping.getAssetType() != null && !mapping.getAssetType().trim().isEmpty()) {
                    assetTypeCache.computeIfAbsent(mapping.getAssetType(), k -> new ArrayList<>()).add(mapping);
                }
            }
            
            // 更新统计信息
            lastRefreshTime.set(System.currentTimeMillis());
            refreshCount.incrementAndGet();
            
            long endTime = System.currentTimeMillis();
            log.info("资产映射缓存刷新完成，共加载 {} 条记录，耗时 {} ms", 
                    allMappings.size(), (endTime - startTime));
                    
        } catch (Exception e) {
            log.error("刷新资产映射缓存失败", e);
            throw new RuntimeException("刷新资产映射缓存失败", e);
        }
    }
    
    @Override
    public EqptMapping getByEqptCode(String eqptCode) {
        if (eqptCode == null || eqptCode.trim().isEmpty()) {
            return null;
        }
        
        EqptMapping mapping = eqptCodeCache.get(eqptCode);
        if (mapping != null) {
            cacheHitCount.incrementAndGet();
        } else {
            cacheMissCount.incrementAndGet();
        }
        return mapping;
    }
    
    @Override
    public EqptMapping getByBmsCode(String bmsCode) {
        if (bmsCode == null || bmsCode.trim().isEmpty()) {
            return null;
        }
        
        EqptMapping mapping = bmsCodeCache.get(bmsCode);
        if (mapping != null) {
            cacheHitCount.incrementAndGet();
        } else {
            cacheMissCount.incrementAndGet();
        }
        return mapping;
    }
    
    @Override
    public EqptMapping getByAssetCode(String assetCode) {
        if (assetCode == null || assetCode.trim().isEmpty()) {
            return null;
        }
        
        EqptMapping mapping = assetCodeCache.get(assetCode);
        if (mapping != null) {
            cacheHitCount.incrementAndGet();
        } else {
            cacheMissCount.incrementAndGet();
        }
        return mapping;
    }
    
    @Override
    public EqptMapping getByBaCode(String baCode) {
        if (baCode == null || baCode.trim().isEmpty()) {
            return null;
        }
        
        EqptMapping mapping = baCodeCache.get(baCode);
        if (mapping != null) {
            cacheHitCount.incrementAndGet();
        } else {
            cacheMissCount.incrementAndGet();
        }
        return mapping;
    }
    
    @Override
    public List<EqptMapping> getAllMappings() {
        return new ArrayList<>(eqptCodeCache.values());
    }
    
    @Override
    public List<EqptMapping> getByAssetType(String assetType) {
        if (assetType == null || assetType.trim().isEmpty()) {
            return new ArrayList<>();
        }
        
        List<EqptMapping> mappings = assetTypeCache.get(assetType);
        if (mappings != null) {
            cacheHitCount.incrementAndGet();
            return new ArrayList<>(mappings);
        } else {
            cacheMissCount.incrementAndGet();
            return new ArrayList<>();
        }
    }
    
    @Override
    public Map<String, Object> getCacheStats() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalMappings", eqptCodeCache.size());
        stats.put("cacheHitCount", cacheHitCount.get());
        stats.put("cacheMissCount", cacheMissCount.get());
        stats.put("lastRefreshTime", new Date(lastRefreshTime.get()));
        stats.put("refreshCount", refreshCount.get());
        
        // 计算缓存命中率
        long totalRequests = cacheHitCount.get() + cacheMissCount.get();
        double hitRate = totalRequests > 0 ? (double) cacheHitCount.get() / totalRequests * 100 : 0;
        stats.put("hitRate", String.format("%.2f%%", hitRate));
        
        return stats;
    }
    
    /**
     * 清空所有缓存
     */
    private void clearCache() {
        eqptCodeCache.clear();
        bmsCodeCache.clear();
        assetCodeCache.clear();
        baCodeCache.clear();
        assetTypeCache.clear();
    }
}
